import java.io.*;
import java.net.*;



public class ServerThread extends Thread {
        private Server server;
        private Socket playerSocket;
       
        private int playerID;
        private String playerName;

        /**
         * Constructor of the thread.
         * @param server Server's socket.
         * @param playerSocket Player's socket.
         * @param playerId Player ID.
         */
        public ServerThread(Server server, Socket playerSocket, int playerId) {
                super("Player-" + playerId);
               
                this.server = server;
                this.playerSocket = playerSocket;
                this.playerID = playerId;

                start();
        }
       
       
        /**
         * Main thread's method.
         * Read requests sending by player.
         */
        public void run() {
                try {
                        DataInputStream reader = new DataInputStream(playerSocket.getInputStream());
                        DataOutputStream writer = new DataOutputStream(playerSocket.getOutputStream());
                       
                       
                        writer.writeUTF("numberOfPlayers " + server.numberOfPlayers);
                        writer.writeUTF("yourID " + playerID);
                        writer.writeUTF("yourCards " + returnPlayerCards());
                        writer.writeUTF("yourChips " + server.playerChips[playerID-1]);

                       
                        while (true) {
                                String request = reader.readUTF();
                           
                                if (request == null) {
                                        continue;
                                }
                           
                                String[] tab = request.split(" ");
                                String cmd = tab[0];


                                if (cmd.equalsIgnoreCase("setPlayerName")) {
                                        writer.writeUTF("yourName " + validatePlayerName(tab[1]));
                                       
                                        server.players[playerID-1] = playerName;
                                       
                                        server.sendToAll(color("&nbsp; New player: " + bold(playerName), "#00b4ff"));
                                        server.sendToAll("tableUpdate newPlayer " + playerID + " " + playerName);
                                       
                                        String str = "";
                                       
                                        for (int i = 0; i < server.numberOfPlayers; i++) {
                                                if (server.playerStatus[i] == true)
                                                        str += " " + (i+1) + " " + server.players[i];
                                        }
                                       
                                        writer.writeUTF("tableUpdate allCurrentPlayers" + str);
                                       
                                        if (server.numberOfCurrentPlayers == server.numberOfPlayers && !server.gameStarted) {
                                                boolean tmp = true;
                                               
                                                for (int i = 0; i < server.numberOfPlayers; i++) {
                                                        if (server.players[i] == null) {
                                                                tmp = false;
                                                                break;
                                                        }
                                                }
                                               
                                                if (tmp)
                                                        server.beginNewGame();
                                        }
                                       
                                } else if (cmd.equalsIgnoreCase("returnMyCards")) {
                                        writer.writeUTF("yourCards " + returnPlayerCards());
                               
                                } else if (cmd.equalsIgnoreCase("returnMyChips")) {
                                        writer.writeUTF("yourChips " + server.playerChips[playerID-1]);
                                       
                                } else if (cmd.equalsIgnoreCase("numberOfPlayers")) {
                                        writer.writeUTF("numberOfPlayers " + server.numberOfPlayers);
                                       
                                } else if (cmd.equalsIgnoreCase("dontDrawMyCards")) {
                                        if (server.registerPlayerMove(playerID, writer, "dontDrawMyCards", null)) {
                                                checkGameStatus(true);          
                                        }
                                       
                                } else if (cmd.equalsIgnoreCase("drawMyCards")) {
                                        if (server.registerPlayerMove(playerID, writer, "drawMyCards", (tab.length-1) + "")) {
                                                server.drawCards(playerID, request);
                                                writer.writeUTF("yourCards " + returnPlayerCards());
                                               
                                                if (tab.length-1 > 1) {
                                                        server.sendToAll(color("&nbsp; Player " + bold(playerName) + " drew " + (tab.length-1) + " cards.", "#9f9696"));
                                                } else {
                                                        server.sendToAll(color("&nbsp; Player " + bold(playerName) + " drew 1 card.", "#9f9696"));
                                                }
                                               
                                                checkGameStatus(true);
                                        }
                                       
                                } else if (cmd.equalsIgnoreCase("check")) {
                                        if (server.registerPlayerMove(playerID, writer, "check", null)) {
                                                checkGameStatus(false);
                                        }
                                       
                                } else if (cmd.equalsIgnoreCase("bet")) {
                                        if (server.registerPlayerMove(playerID, writer, "bet", tab[1])) {
                                                checkGameStatus(false);
                                        }
                                       
                                } else if (cmd.equalsIgnoreCase("raise")) {
                                        if (server.registerPlayerMove(playerID, writer, "raise", tab[1])) {
                                                checkGameStatus(false);
                                        }

                                } else if (cmd.equalsIgnoreCase("call")) {
                                        if (server.registerPlayerMove(playerID, writer, "call", null)) {
                                                checkGameStatus(false);
                                        }

                                } else if (cmd.equalsIgnoreCase("allIn")) {
                                        if (server.registerPlayerMove(playerID, writer, "allIn", null)) {
                                                checkGameStatus(false);
                                        }

                                } else if (cmd.equalsIgnoreCase("fold")) {
                                        server.registerPlayerMove(playerID, writer, "fold", null);
                                        server.removeConnection(playerSocket, playerName, playerID);
                                        checkGameStatus(false);
                                       
                                        break;
                                       
                                } else if (cmd.equalsIgnoreCase("nextGameYes")) {
                                        server.numberOfCurrentPlayers += 1;
                                       
                                        server.sendToAll(color("&nbsp; " + bold(playerName) + " wants to play again.", "#c836bb"));
                                       
                                        writer.writeUTF("yourCards " + returnPlayerCards());
                                        writer.writeUTF("yourChips " + server.playerChips[playerID-1]);
                                       

                                        if (server.numberOfCurrentPlayers == server.numberOfPlayers) {
                                                server.beginNewGame();
                                        }
                                       
                                } else if (cmd.equalsIgnoreCase("nextGameNo")) {
                                        server.removeConnection(playerSocket, playerName, playerID);
                                        server.sendToAll("tableUpdate playerGaveUpGame " + playerID + " " + playerName);
                                       
                                        if (!server.allowNewPlayers) {
                                                server.allowNewPlayers = true;
                                               
                                                try {
                                                        server.listen();
                                                } catch (Exception e) {
                                                        System.out.println(" > Cannot listen.");
                                                }
                                        }
                                       
                                        return;
                                }
                        }
                } catch (Exception e) {
                        if (server.gameStarted) {
                                server.registerPseudoFold(playerID, playerName);
                        } else {
                                server.numberOfCurrentPlayers -= 1;
                        }
                       
                       
                        server.removeConnection(playerSocket, playerName, playerID);
                       
                       
                        if (server.gameStarted) {
                                server.sendToAll("tableUpdate fold " + playerID);
                               
                                int nextPlayerID = server.nextPlayer(playerID);
                                String[] roundStatus = server.isEndOf(nextPlayerID);
                               
                                if (roundStatus[0].equals("true")) {
                                        if (roundStatus[1].equals("true")) {
                                               
                                                server.chooseWinner();
       
                                        } else {
                                                server.sendToAll("endOfRound " + roundStatus[2]);
                                                server.sendToAll("newRound " + (Integer.parseInt(roundStatus[2])+1));
                                        }
                                }
                        }
                }
               
                return;
        }
       
       
        /**
         * Method checks current game/ round is over.
         * @param isDrawingRound If current round is a round for drawing cards.
         */
        private void checkGameStatus(boolean isDrawingRound) {
                if (isDrawingRound) {
                        String[] roundStatus = server.isEndOf(0);
               
                        if (roundStatus[0].equals("true")) {
                                if (roundStatus[1].equals("true")) {
                               
                                        server.chooseWinner();
                               
                                } else {
                                        server.sendToAll("endOfRound " + roundStatus[2]);
                                        server.sendToAll("newRound " + (Integer.parseInt(roundStatus[2])+1));
                                        server.sendToAll("nextPlayerMove " + server.smallBlindHolder + " " + server.players[server.smallBlindHolder-1] + " " + server.possiblePlayerMoves(server.smallBlindHolder));
                                }
                }  
                } else {
                        int nextPlayerID = server.nextPlayer(playerID);
                        String[] roundStatus = server.isEndOf(nextPlayerID);
                       
                       
                        if (roundStatus[0].equals("true")) {
                                if (roundStatus[1].equals("true")) {
                                       
                                        server.chooseWinner();

                                } else {
                                        server.sendToAll("endOfRound " + roundStatus[2]);
                                        server.sendToAll("newRound " + (Integer.parseInt(roundStatus[2])+1));
                                }
                        } else {
                                server.sendToAll("nextPlayerMove " + nextPlayerID + " " + server.players[nextPlayerID-1] + " " + server.possiblePlayerMoves(nextPlayerID));
                        }
                }
        }
       
       
        /**
         * @return String containing 4 substrings (player cards in format: VALUE-COLOR, for ex.:
         * 8-Black-Spade).
         */
        private String returnPlayerCards() {
                String cards = "";
                int firstCardIndex = (playerID - 1) * 4;
                       
                for (int i = firstCardIndex; i <= firstCardIndex + 3; i++) {
                        cards += server.playerCards[i] + " ";
                }
               
                return cards;
        }
       
       
        /**
         * Checks if player name is unique.
         * @param name Player name to check.
         * @return Validated player name. If is unique method returns input string, if not, String
         * which is unique player name.
         */
        private String validatePlayerName(String name) {
                try {

                        if (name == null || name.equalsIgnoreCase("null")) {
                                name = "Player-" + playerID;
                        } else {
                                boolean tmp = true;
                               
                                while (tmp) {
                                        tmp = false;
                                       
                                        for (int i = 0; i < server.numberOfPlayers; i++) {
                                                if (name.equals(server.players[i])) {
                                                        name += "-1";
                                                        tmp = true;
                                                }
                                        }
                                }
                        }

                } catch (Exception e) {
                        name = "Player-" + playerID;
                }
               
                playerName = name;
                return name;
        }
       
       
        /**
         * @param str String to bold.
         * @return String with HTML brackets (b).
         */
        private String bold(String str) {
                return "<b>" + str + "</b>";
        }
       
       
        /**
         * @param str Input string.
         * @param color Color (for ex.: orange, yellow or #000000).
         * @return A string with HTML brackets (span) with in-line style.
         */
        private String color(String str, String color) {
                return "<span style=\"color:" + color + ";\">" + str + "</span>";
        }
}

